{
 "cells": [
  {
   "cell_type": "code",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-28T06:08:56.045695Z",
     "start_time": "2025-02-28T06:08:56.008919Z"
    }
   },
   "source": [
    "import matplotlib as mpl\n",
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline\n",
    "import numpy as np\n",
    "import sklearn\n",
    "import pandas as pd\n",
    "import os\n",
    "import sys\n",
    "import time\n",
    "from tqdm.auto import tqdm\n",
    "import torch\n",
    "import torch.nn as nn\n",
    "import torch.nn.functional as F\n",
    "\n",
    "print(sys.version_info)\n",
    "for module in mpl, np, pd, sklearn, torch:\n",
    "    print(module.__name__, module.__version__)\n",
    "    \n",
    "device = torch.device(\"cuda:0\") if torch.cuda.is_available() else torch.device(\"cpu\")\n",
    "print(device)\n",
    "\n",
    "seed = 42\n"
   ],
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "sys.version_info(major=3, minor=12, micro=3, releaselevel='final', serial=0)\n",
      "matplotlib 3.10.0\n",
      "numpy 2.0.2\n",
      "pandas 2.2.3\n",
      "sklearn 1.6.1\n",
      "torch 2.6.0+cu126\n",
      "cuda:0\n"
     ]
    }
   ],
   "execution_count": 16
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 数据准备\n",
    "\n",
    "```shell\n",
    "$ tree -L 1 cifar-10                                    \n",
    "cifar-10\n",
    "├── sampleSubmission.csv\n",
    "├── test\n",
    "├── train\n",
    "└── trainLabels.csv\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-28T06:08:57.959346Z",
     "start_time": "2025-02-28T06:08:56.055733Z"
    }
   },
   "source": [
    "from pathlib import Path\n",
    "\n",
    "DATA_DIR = Path(\"D:/Python/Python_code/Python_code2025/day23/cifar-10\")\n",
    "\n",
    "train_lables_file = DATA_DIR / \"trainLabels.csv\"\n",
    "test_csv_file = DATA_DIR / \"sampleSubmission.csv\" #测试集模板csv文件\n",
    "train_folder = DATA_DIR / \"train\"\n",
    "test_folder = DATA_DIR / \"test\"\n",
    "\n",
    "#所有的类别\n",
    "class_names = [\n",
    "    'airplane',\n",
    "    'automobile',\n",
    "    'bird',\n",
    "    'cat',\n",
    "    'deer',\n",
    "    'dog',\n",
    "    'frog',\n",
    "    'horse',\n",
    "    'ship',\n",
    "    'truck',\n",
    "]\n",
    "\n",
    "def parse_csv_file(filepath, folder): #filepath:csv文件路径，folder:图片所在文件夹\n",
    "    \"\"\"Parses csv files into (filename(path), label) format\"\"\"\n",
    "    results = []\n",
    "    #读取所有行\n",
    "    with open(filepath, 'r') as f:\n",
    "#         lines = f.readlines()  为什么加[1:]，可以试这个\n",
    "        #第一行不需要，因为第一行是标题\n",
    "        lines = f.readlines()[1:] \n",
    "    for line in lines:#依次去取每一行\n",
    "        image_id, label_str = line.strip('\\n').split(',') #图片id 和标签分离\n",
    "        image_full_path = folder / f\"{image_id}.png\"\n",
    "        results.append((image_full_path, label_str)) #得到对应图片的路径和分类\n",
    "    return results\n",
    "\n",
    "#解析对应的文件夹\n",
    "train_labels_info = parse_csv_file(train_lables_file, train_folder)\n",
    "test_csv_info = parse_csv_file(test_csv_file, test_folder)\n",
    "#打印\n",
    "import pprint\n",
    "pprint.pprint(train_labels_info[0:5])\n",
    "pprint.pprint(test_csv_info[0:5])\n",
    "print(len(train_labels_info), len(test_csv_info))"
   ],
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[(WindowsPath('D:/Python/Python_code/Python_code2025/day23/cifar-10/train/1.png'),\n",
      "  'frog'),\n",
      " (WindowsPath('D:/Python/Python_code/Python_code2025/day23/cifar-10/train/2.png'),\n",
      "  'truck'),\n",
      " (WindowsPath('D:/Python/Python_code/Python_code2025/day23/cifar-10/train/3.png'),\n",
      "  'truck'),\n",
      " (WindowsPath('D:/Python/Python_code/Python_code2025/day23/cifar-10/train/4.png'),\n",
      "  'deer'),\n",
      " (WindowsPath('D:/Python/Python_code/Python_code2025/day23/cifar-10/train/5.png'),\n",
      "  'automobile')]\n",
      "[(WindowsPath('D:/Python/Python_code/Python_code2025/day23/cifar-10/test/1.png'),\n",
      "  'cat'),\n",
      " (WindowsPath('D:/Python/Python_code/Python_code2025/day23/cifar-10/test/2.png'),\n",
      "  'cat'),\n",
      " (WindowsPath('D:/Python/Python_code/Python_code2025/day23/cifar-10/test/3.png'),\n",
      "  'cat'),\n",
      " (WindowsPath('D:/Python/Python_code/Python_code2025/day23/cifar-10/test/4.png'),\n",
      "  'cat'),\n",
      " (WindowsPath('D:/Python/Python_code/Python_code2025/day23/cifar-10/test/5.png'),\n",
      "  'cat')]\n",
      "50000 300000\n"
     ]
    }
   ],
   "execution_count": 17
  },
  {
   "cell_type": "code",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-28T06:08:58.022965Z",
     "start_time": "2025-02-28T06:08:57.959346Z"
    }
   },
   "source": [
    "# train_df = pd.DataFrame(train_labels_info)\n",
    "train_df = pd.DataFrame(train_labels_info[0:45000]) # 取前45000张图片作为训练集\n",
    "valid_df = pd.DataFrame(train_labels_info[45000:]) # 取后5000张图片作为验证集\n",
    "test_df = pd.DataFrame(test_csv_info)\n",
    "\n",
    "train_df.columns = ['filepath', 'class']\n",
    "valid_df.columns = ['filepath', 'class']\n",
    "test_df.columns = ['filepath', 'class']\n",
    "\n",
    "print(train_df.head())\n",
    "print(valid_df.head())\n",
    "print(test_df.head())"
   ],
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "                                            filepath       class\n",
      "0  D:\\Python\\Python_code\\Python_code2025\\day23\\ci...        frog\n",
      "1  D:\\Python\\Python_code\\Python_code2025\\day23\\ci...       truck\n",
      "2  D:\\Python\\Python_code\\Python_code2025\\day23\\ci...       truck\n",
      "3  D:\\Python\\Python_code\\Python_code2025\\day23\\ci...        deer\n",
      "4  D:\\Python\\Python_code\\Python_code2025\\day23\\ci...  automobile\n",
      "                                            filepath       class\n",
      "0  D:\\Python\\Python_code\\Python_code2025\\day23\\ci...       horse\n",
      "1  D:\\Python\\Python_code\\Python_code2025\\day23\\ci...  automobile\n",
      "2  D:\\Python\\Python_code\\Python_code2025\\day23\\ci...        deer\n",
      "3  D:\\Python\\Python_code\\Python_code2025\\day23\\ci...  automobile\n",
      "4  D:\\Python\\Python_code\\Python_code2025\\day23\\ci...    airplane\n",
      "                                            filepath class\n",
      "0  D:\\Python\\Python_code\\Python_code2025\\day23\\ci...   cat\n",
      "1  D:\\Python\\Python_code\\Python_code2025\\day23\\ci...   cat\n",
      "2  D:\\Python\\Python_code\\Python_code2025\\day23\\ci...   cat\n",
      "3  D:\\Python\\Python_code\\Python_code2025\\day23\\ci...   cat\n",
      "4  D:\\Python\\Python_code\\Python_code2025\\day23\\ci...   cat\n"
     ]
    }
   ],
   "execution_count": 18
  },
  {
   "cell_type": "code",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-28T06:08:58.030838Z",
     "start_time": "2025-02-28T06:08:58.022965Z"
    }
   },
   "source": [
    "from PIL import Image\n",
    "from torch.utils.data import Dataset, DataLoader\n",
    "from torchvision import transforms\n",
    "\n",
    "class Cifar10Dataset(Dataset):\n",
    "    df_map = {\n",
    "        \"train\": train_df,\n",
    "        \"eval\": valid_df,\n",
    "        \"test\": test_df\n",
    "    }\n",
    "    label_to_idx = {label: idx for idx, label in enumerate(class_names)} # 类别映射为idx\n",
    "    idx_to_label = {idx: label for idx, label in enumerate(class_names)} # idx映射为类别,为了test测试集使用\n",
    "    def __init__(self, mode, transform=None):\n",
    "        self.df = self.df_map.get(mode, None) # 获取对应模式的df，不同字符串对应不同模式\n",
    "        if self.df is None:\n",
    "            raise ValueError(\"mode should be one of train, val, test, but got {}\".format(mode))\n",
    "        # assert self.df, \"df is None\"\n",
    "        self.transform = transform\n",
    "        \n",
    "    def __getitem__(self, index):\n",
    "        img_path, label = self.df.iloc[index] # 获取图片路径和标签\n",
    "        img = Image.open(img_path).convert('RGB')\n",
    "        # # img 转换为 channel first\n",
    "        # img = img.transpose((2, 0, 1))\n",
    "        # transform\n",
    "        img = self.transform(img) # 数据增强\n",
    "        # label 转换为 idx\n",
    "        label = self.label_to_idx[label]\n",
    "        return img, label\n",
    "    \n",
    "    def __len__(self):\n",
    "        return self.df.shape[0] # 返回df的行数,样本数\n",
    "    \n",
    "IMAGE_SIZE = 32\n",
    "mean, std = [0.4914, 0.4822, 0.4465], [0.247, 0.243, 0.261]\n",
    "\n",
    "transforms_train = transforms.Compose([\n",
    "        # resize\n",
    "        transforms.Resize((IMAGE_SIZE, IMAGE_SIZE)), #缩放\n",
    "        # random rotation 40\n",
    "        transforms.RandomRotation(40), #随机旋转\n",
    "        # horizaontal flip\n",
    "        transforms.RandomHorizontalFlip(),  #随机水平翻转\n",
    "        transforms.ToTensor(), #转换为tensor\n",
    "        # transforms.Normalize(mean, std) #标准化\n",
    "    ]) #数据增强\n",
    "\n",
    "transforms_eval = transforms.Compose([\n",
    "        # resize\n",
    "        transforms.Resize((IMAGE_SIZE, IMAGE_SIZE)),\n",
    "        transforms.ToTensor(),\n",
    "        transforms.Normalize(mean, std)\n",
    "    ])\n",
    "# ToTensor还将图像的维度从[height, width, channels]转换为[channels, height, width]。\n",
    "train_ds = Cifar10Dataset(\"train\", transforms_train)\n",
    "eval_ds = Cifar10Dataset(\"eval\", transforms_eval)"
   ],
   "outputs": [],
   "execution_count": 19
  },
  {
   "cell_type": "code",
   "source": [
    "train_ds[0][0].shape # 图片的shape,输入"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2025-02-28T06:08:58.130369Z",
     "start_time": "2025-02-28T06:08:58.031349Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([3, 32, 32])"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 20
  },
  {
   "cell_type": "code",
   "source": [
    "print(train_ds.idx_to_label)  # 类别映射为idx\n",
    "train_ds.label_to_idx # idx映射为类别"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2025-02-28T06:08:58.134500Z",
     "start_time": "2025-02-28T06:08:58.130369Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{0: 'airplane', 1: 'automobile', 2: 'bird', 3: 'cat', 4: 'deer', 5: 'dog', 6: 'frog', 7: 'horse', 8: 'ship', 9: 'truck'}\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "{'airplane': 0,\n",
       " 'automobile': 1,\n",
       " 'bird': 2,\n",
       " 'cat': 3,\n",
       " 'deer': 4,\n",
       " 'dog': 5,\n",
       " 'frog': 6,\n",
       " 'horse': 7,\n",
       " 'ship': 8,\n",
       " 'truck': 9}"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 21
  },
  {
   "cell_type": "code",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-28T06:08:58.137813Z",
     "start_time": "2025-02-28T06:08:58.134500Z"
    }
   },
   "source": [
    "batch_size = 64\n",
    "train_dl = DataLoader(train_ds, batch_size=batch_size, shuffle=True)   \n",
    "eval_dl = DataLoader(eval_ds, batch_size=batch_size, shuffle=False)"
   ],
   "outputs": [],
   "execution_count": 22
  },
  {
   "cell_type": "code",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-28T06:12:50.946859Z",
     "start_time": "2025-02-28T06:08:58.137813Z"
    }
   },
   "source": [
    "# 遍历train_ds得到每张图片，计算每个通道的均值和方差\n",
    "def cal_mean_std(ds):\n",
    "    mean = 0.\n",
    "    std = 0.\n",
    "    for img, _ in ds:\n",
    "        mean += img.mean(dim=(1, 2))\n",
    "        std += img.std(dim=(1, 2))\n",
    "    mean /= len(ds)\n",
    "    std /= len(ds)\n",
    "    return mean, std\n",
    "\n",
    "# 经过 normalize 后 均值为0，方差为1\n",
    "print(cal_mean_std(train_ds))"
   ],
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(tensor([0.4369, 0.4268, 0.3947]), tensor([0.2465, 0.2419, 0.2360]))\n"
     ]
    }
   ],
   "execution_count": 23
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 定义模型"
   ]
  },
  {
   "cell_type": "code",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-28T06:12:50.998878Z",
     "start_time": "2025-02-28T06:12:50.946859Z"
    }
   },
   "source": [
    "class CNN(nn.Module):\n",
    "    def __init__(self, num_classes):\n",
    "        super().__init__()\n",
    "        self.model = nn.Sequential(\n",
    "            nn.Conv2d(in_channels=3, out_channels=128, kernel_size=3, padding=\"same\"),\n",
    "            nn.ReLU(),\n",
    "            nn.BatchNorm2d(128),# 批标准化，在通道数做的归一化\n",
    "            nn.Conv2d(in_channels=128, out_channels=128, kernel_size=3, padding=\"same\"), #输出尺寸（128，32，32）\n",
    "            nn.ReLU(),\n",
    "            nn.BatchNorm2d(128),\n",
    "            nn.MaxPool2d(kernel_size=2), #输出尺寸（128，16，16）\n",
    "            nn.Conv2d(in_channels=128, out_channels=256, kernel_size=3, padding=\"same\"),\n",
    "            nn.ReLU(),\n",
    "            nn.BatchNorm2d(256),\n",
    "            nn.Conv2d(in_channels=256, out_channels=256, kernel_size=3, padding=\"same\"), #输出尺寸（256，16，16）\n",
    "            nn.ReLU(),\n",
    "            nn.BatchNorm2d(256),\n",
    "            nn.MaxPool2d(kernel_size=2),#输出尺寸（256，8，8）\n",
    "            nn.Conv2d(in_channels=256, out_channels=512, kernel_size=3, padding=\"same\"),\n",
    "            nn.ReLU(),\n",
    "            nn.BatchNorm2d(512),\n",
    "            nn.Conv2d(in_channels=512, out_channels=512, kernel_size=3, padding=\"same\"), #输出尺寸（512，8，8）\n",
    "            nn.ReLU(),\n",
    "            nn.BatchNorm2d(512),\n",
    "            nn.MaxPool2d(kernel_size=2), #输出尺寸（512，4，4）\n",
    "            nn.Flatten(), #展平\n",
    "            nn.Linear(8192, 512),\n",
    "            nn.ReLU(),\n",
    "            nn.Linear(512, num_classes),\n",
    "        ) #Sequential自动连接各层，把各层的输出作为下一层的输入\n",
    "        \n",
    "    def forward(self, x):\n",
    "        return self.model(x)\n",
    "        \n",
    "for key, value in CNN(len(class_names)).named_parameters():\n",
    "    print(f\"{key:^40}paramerters num: {np.prod(value.shape)}\")\n",
    "    \n"
   ],
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "             model.0.weight             paramerters num: 3456\n",
      "              model.0.bias              paramerters num: 128\n",
      "             model.2.weight             paramerters num: 128\n",
      "              model.2.bias              paramerters num: 128\n",
      "             model.3.weight             paramerters num: 147456\n",
      "              model.3.bias              paramerters num: 128\n",
      "             model.5.weight             paramerters num: 128\n",
      "              model.5.bias              paramerters num: 128\n",
      "             model.7.weight             paramerters num: 294912\n",
      "              model.7.bias              paramerters num: 256\n",
      "             model.9.weight             paramerters num: 256\n",
      "              model.9.bias              paramerters num: 256\n",
      "            model.10.weight             paramerters num: 589824\n",
      "             model.10.bias              paramerters num: 256\n",
      "            model.12.weight             paramerters num: 256\n",
      "             model.12.bias              paramerters num: 256\n",
      "            model.14.weight             paramerters num: 1179648\n",
      "             model.14.bias              paramerters num: 512\n",
      "            model.16.weight             paramerters num: 512\n",
      "             model.16.bias              paramerters num: 512\n",
      "            model.17.weight             paramerters num: 2359296\n",
      "             model.17.bias              paramerters num: 512\n",
      "            model.19.weight             paramerters num: 512\n",
      "             model.19.bias              paramerters num: 512\n",
      "            model.22.weight             paramerters num: 4194304\n",
      "             model.22.bias              paramerters num: 512\n",
      "            model.24.weight             paramerters num: 5120\n",
      "             model.24.bias              paramerters num: 10\n"
     ]
    }
   ],
   "execution_count": 24
  },
  {
   "cell_type": "code",
   "source": [
    "total_params = sum(p.numel() for p in CNN(len(class_names)).parameters() if p.requires_grad)\n",
    "print(f\"Total trainable parameters: {total_params}\")"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2025-02-28T06:12:51.035074Z",
     "start_time": "2025-02-28T06:12:50.998878Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Total trainable parameters: 8779914\n"
     ]
    }
   ],
   "execution_count": 25
  },
  {
   "cell_type": "code",
   "source": [
    "512*4*4"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2025-02-28T06:12:51.040237Z",
     "start_time": "2025-02-28T06:12:51.035584Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "8192"
      ]
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 26
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-28T06:12:51.058520Z",
     "start_time": "2025-02-28T06:12:51.040237Z"
    }
   },
   "cell_type": "code",
   "source": [
    "input_4d = torch.randn(32, 3, 64, 64)  # 32 个样本，3 个通道，图像大小为 64x64\n",
    "bn2d = nn.BatchNorm2d(3)              # 对 3 个通道进行归一化\n",
    "output_4d = bn2d(input_4d)\n",
    "output_4d.shape"
   ],
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([32, 3, 64, 64])"
      ]
     },
     "execution_count": 27,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 27
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-28T06:12:51.077348Z",
     "start_time": "2025-02-28T06:12:51.058520Z"
    }
   },
   "cell_type": "code",
   "source": "output_4d",
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([[[[ 1.8569e-01,  1.2068e+00,  1.3107e+00,  ...,  4.3335e-01,\n",
       "            9.5957e-01, -4.6191e-01],\n",
       "          [-1.2491e-01, -3.4355e-01, -2.9710e-01,  ...,  5.3335e-01,\n",
       "            1.0790e-01,  9.8546e-01],\n",
       "          [ 1.6000e+00,  1.4632e+00, -9.4793e-01,  ..., -1.3305e-01,\n",
       "            8.2460e-01, -1.5341e+00],\n",
       "          ...,\n",
       "          [-1.7832e-01, -1.9131e-01,  1.3213e+00,  ..., -1.0020e+00,\n",
       "           -1.7615e-01, -9.9070e-01],\n",
       "          [ 1.1259e+00,  7.0162e-01, -1.7411e+00,  ...,  1.5110e+00,\n",
       "           -7.8733e-01,  9.8757e-01],\n",
       "          [ 1.3298e+00,  4.9607e-01,  6.7348e-01,  ...,  2.6917e-01,\n",
       "            5.4652e-01,  9.8298e-01]],\n",
       "\n",
       "         [[ 3.5681e-01,  1.5646e+00,  1.5560e-01,  ...,  5.3458e-01,\n",
       "            1.5919e+00,  7.4984e-01],\n",
       "          [-2.1030e+00,  1.8096e+00,  1.8354e+00,  ..., -1.6142e-01,\n",
       "            4.2707e-01,  4.1784e-01],\n",
       "          [ 7.9315e-01,  9.9420e-02,  7.3650e-01,  ...,  8.7391e-01,\n",
       "            3.5900e-02, -2.2920e+00],\n",
       "          ...,\n",
       "          [ 4.3190e-01,  2.5048e-01,  6.0206e-01,  ..., -1.6290e+00,\n",
       "           -1.7746e+00, -1.8020e+00],\n",
       "          [-6.2905e-02,  5.7528e-01,  8.6430e-01,  ...,  1.2655e+00,\n",
       "            1.8034e+00,  1.2188e+00],\n",
       "          [ 6.8550e-01, -1.4461e+00, -1.3477e+00,  ..., -1.0422e+00,\n",
       "            6.2141e-01, -1.1038e+00]],\n",
       "\n",
       "         [[ 1.7910e+00,  5.0520e-01,  8.7792e-01,  ..., -1.4809e+00,\n",
       "            1.9882e+00,  7.4995e-02],\n",
       "          [ 1.3568e+00,  9.8552e-01,  9.8968e-02,  ..., -9.8872e-01,\n",
       "            3.8829e-01,  9.2142e-01],\n",
       "          [-4.8152e-01,  6.1456e-01, -1.0375e-01,  ..., -1.3428e+00,\n",
       "           -1.1931e+00, -7.0046e-01],\n",
       "          ...,\n",
       "          [-7.5990e-01, -2.0112e+00,  1.2381e-01,  ..., -5.2412e-01,\n",
       "           -1.8966e-01,  4.7841e-01],\n",
       "          [-9.0537e-02,  6.0932e-01,  6.6987e-02,  ...,  8.8619e-01,\n",
       "            1.8197e+00, -8.1332e-01],\n",
       "          [ 1.2819e+00,  5.5233e-01, -6.7761e-01,  ...,  1.7753e+00,\n",
       "           -7.9193e-02,  9.0512e-01]]],\n",
       "\n",
       "\n",
       "        [[[ 2.1235e-01, -1.3695e+00, -3.8327e-01,  ..., -1.1019e+00,\n",
       "           -1.0343e+00, -2.3676e+00],\n",
       "          [-1.4991e+00,  2.4738e+00,  2.2970e-01,  ..., -1.0718e+00,\n",
       "           -1.2624e+00,  8.9523e-01],\n",
       "          [ 8.4688e-02, -1.4311e+00, -6.3570e-01,  ..., -1.2361e+00,\n",
       "           -1.1776e+00, -2.3710e+00],\n",
       "          ...,\n",
       "          [-4.0124e-01, -3.1967e-01,  5.0613e-01,  ...,  1.0480e+00,\n",
       "           -3.9350e-01, -5.2132e-01],\n",
       "          [ 1.5438e+00,  7.8144e-02,  1.4013e+00,  ...,  2.4039e-01,\n",
       "            2.1614e-01, -1.0379e-01],\n",
       "          [-3.2411e-03, -2.0316e-01, -7.6511e-01,  ...,  2.3886e-01,\n",
       "           -1.9993e-01, -2.3064e-01]],\n",
       "\n",
       "         [[ 2.7442e-01,  9.3399e-01, -1.9005e+00,  ..., -5.7647e-01,\n",
       "           -5.8132e-01,  4.5314e-01],\n",
       "          [-6.9768e-01,  1.1564e+00, -2.4968e-02,  ...,  3.0096e-01,\n",
       "            1.3031e+00, -1.0687e+00],\n",
       "          [-2.1511e-01,  1.8378e+00,  6.6159e-01,  ...,  2.0231e+00,\n",
       "            1.1216e+00,  8.5977e-01],\n",
       "          ...,\n",
       "          [-1.5473e-01,  7.6578e-01, -6.6254e-01,  ..., -9.4947e-01,\n",
       "           -6.9002e-02,  7.7934e-01],\n",
       "          [ 1.8169e+00, -8.8171e-01,  2.4812e-01,  ...,  2.5222e-01,\n",
       "            9.3517e-02, -1.2391e+00],\n",
       "          [ 1.3062e+00,  1.1296e+00, -3.9016e-02,  ..., -8.5133e-01,\n",
       "            6.6556e-01,  4.1476e-01]],\n",
       "\n",
       "         [[ 6.7206e-01,  7.8562e-01, -1.6570e-01,  ...,  3.8123e-01,\n",
       "           -1.3614e+00, -7.7306e-02],\n",
       "          [-2.6972e-01, -4.1896e-01,  1.9627e-01,  ...,  1.0007e+00,\n",
       "            1.5928e+00, -2.7853e-01],\n",
       "          [-2.7662e-01, -1.2288e+00,  1.1122e+00,  ..., -7.7570e-01,\n",
       "           -4.4063e-02,  6.1394e-01],\n",
       "          ...,\n",
       "          [-4.7921e-01, -6.3495e-01,  3.7953e-02,  ...,  5.7571e-01,\n",
       "           -1.9082e-01,  1.6356e+00],\n",
       "          [ 6.4346e-01,  1.5082e+00,  3.4606e-01,  ..., -1.0047e+00,\n",
       "           -3.1302e-01,  3.7256e-02],\n",
       "          [-6.6395e-01, -6.9003e-01, -1.2866e+00,  ..., -1.3429e+00,\n",
       "           -5.9193e-01, -3.8784e-01]]],\n",
       "\n",
       "\n",
       "        [[[ 6.1855e-01, -5.5757e-01, -7.8050e-01,  ...,  1.1679e-01,\n",
       "            9.9641e-04,  1.1030e+00],\n",
       "          [ 7.6553e-01,  1.4823e+00,  1.9650e-01,  ...,  1.8195e-01,\n",
       "           -8.6149e-01,  1.1540e+00],\n",
       "          [ 5.3513e-01, -1.4084e+00,  9.4293e-01,  ...,  8.3426e-01,\n",
       "           -2.4585e-02,  4.4219e-01],\n",
       "          ...,\n",
       "          [ 1.7459e+00,  2.2184e-01,  2.1390e+00,  ..., -6.9334e-01,\n",
       "           -6.6404e-01,  8.6515e-01],\n",
       "          [-5.1798e-01, -1.0526e+00, -1.0209e+00,  ..., -2.1027e+00,\n",
       "            1.8648e+00, -5.9670e-01],\n",
       "          [ 4.7469e-01, -1.2343e+00, -1.6261e-01,  ..., -2.6611e+00,\n",
       "            5.0511e-01,  1.0620e+00]],\n",
       "\n",
       "         [[-1.9498e-01, -7.7828e-01,  9.5335e-02,  ...,  5.3090e-01,\n",
       "            1.1198e+00, -8.1623e-01],\n",
       "          [ 2.0367e-01, -2.6932e-01,  1.7785e-01,  ..., -8.4300e-01,\n",
       "            1.4125e-01, -5.8168e-01],\n",
       "          [-1.0160e+00, -7.3943e-02,  4.0610e-01,  ...,  2.6007e-01,\n",
       "           -2.2885e-01, -6.0394e-01],\n",
       "          ...,\n",
       "          [-1.4028e+00,  2.2445e-01, -2.2725e+00,  ...,  1.5552e+00,\n",
       "            2.2891e-01,  1.7163e+00],\n",
       "          [-2.4023e+00,  2.2531e+00,  4.8489e-01,  ..., -7.7924e-02,\n",
       "           -5.7485e-01, -1.4489e+00],\n",
       "          [-9.1689e-01,  2.9302e-01,  1.2240e+00,  ..., -5.8991e-01,\n",
       "           -8.5928e-01,  4.1167e-01]],\n",
       "\n",
       "         [[ 1.0014e+00, -6.5117e-01,  5.9754e-01,  ...,  1.9475e-01,\n",
       "            2.4795e-01, -7.0052e-01],\n",
       "          [-1.9526e+00,  2.1056e+00,  8.6965e-01,  ..., -5.9461e-01,\n",
       "           -1.0168e+00, -1.7322e+00],\n",
       "          [-6.5174e-01, -6.4039e-01, -1.0696e+00,  ..., -7.6470e-02,\n",
       "            7.6262e-02,  2.0799e-01],\n",
       "          ...,\n",
       "          [-1.3955e+00, -8.8978e-01,  1.1186e+00,  ..., -1.0259e+00,\n",
       "            5.3257e-01,  6.2970e-01],\n",
       "          [-3.3421e-01,  8.6385e-01, -1.1059e+00,  ...,  9.7061e-01,\n",
       "           -5.3919e-02,  4.1184e-02],\n",
       "          [ 2.9329e-01,  9.4322e-02, -1.4479e+00,  ..., -4.4552e-01,\n",
       "            8.6291e-01,  1.0395e-01]]],\n",
       "\n",
       "\n",
       "        ...,\n",
       "\n",
       "\n",
       "        [[[-1.1727e+00, -8.9828e-01, -1.2812e+00,  ..., -1.3389e-01,\n",
       "            2.6161e-01, -2.7735e-01],\n",
       "          [-1.1142e+00,  9.0828e-01,  5.3890e-02,  ..., -4.1168e-01,\n",
       "            7.6607e-01,  3.3931e-01],\n",
       "          [-1.3843e+00, -3.6305e-01,  6.1533e-01,  ..., -1.5851e-01,\n",
       "           -1.0250e+00, -1.2118e+00],\n",
       "          ...,\n",
       "          [ 2.2697e-01, -4.8767e-01,  1.6945e+00,  ...,  5.2397e-01,\n",
       "           -7.3892e-02, -8.0259e-01],\n",
       "          [ 4.3746e-01,  1.9619e+00,  1.6555e+00,  ..., -8.4203e-01,\n",
       "            1.5130e-01,  6.3055e-02],\n",
       "          [ 2.6801e-01,  1.8562e+00,  2.1875e-01,  ...,  3.8246e-01,\n",
       "            1.7874e+00, -3.3015e-01]],\n",
       "\n",
       "         [[ 6.3026e-03, -4.7157e-01, -3.1526e-01,  ...,  5.7434e-01,\n",
       "           -1.5184e+00,  7.8633e-01],\n",
       "          [-2.4746e+00, -7.8442e-01, -1.0035e+00,  ...,  1.6578e+00,\n",
       "            1.1425e+00, -2.1875e+00],\n",
       "          [-3.3174e-01, -5.2836e-01,  1.8805e+00,  ...,  1.5063e-01,\n",
       "           -2.8628e-01, -9.7264e-01],\n",
       "          ...,\n",
       "          [-1.7567e+00,  1.5902e-01,  1.7154e+00,  ...,  1.2679e-01,\n",
       "           -1.1887e+00, -6.9728e-01],\n",
       "          [-7.8431e-01,  3.6647e-01,  1.5458e+00,  ..., -9.8306e-01,\n",
       "           -1.0491e-01, -4.9528e-01],\n",
       "          [ 1.0317e+00, -1.3063e-01,  4.6304e-01,  ..., -1.5412e+00,\n",
       "           -1.0603e-01,  1.1998e+00]],\n",
       "\n",
       "         [[ 5.1780e-02,  5.6883e-02, -6.1304e-01,  ..., -1.5359e+00,\n",
       "           -6.9960e-01, -4.3620e-01],\n",
       "          [ 9.7937e-01, -7.8664e-01,  1.5313e+00,  ...,  1.8891e+00,\n",
       "           -6.6350e-01, -6.2295e-01],\n",
       "          [-3.1199e-02, -5.1996e-01,  2.1627e+00,  ..., -1.8907e+00,\n",
       "           -8.1992e-01,  7.3316e-02],\n",
       "          ...,\n",
       "          [-2.3568e-01, -2.2134e-01,  4.7892e-01,  ...,  1.3269e+00,\n",
       "           -1.3862e+00, -9.1323e-01],\n",
       "          [-3.0327e-01,  7.4321e-01, -1.9894e+00,  ...,  4.4355e-01,\n",
       "           -8.5102e-01,  2.3706e+00],\n",
       "          [ 2.1684e+00, -4.1929e-02, -7.0923e-01,  ...,  3.0846e-01,\n",
       "           -1.0727e+00,  7.9445e-01]]],\n",
       "\n",
       "\n",
       "        [[[-7.3067e-02, -2.1989e-01, -7.8913e-01,  ...,  1.4875e-01,\n",
       "            8.8678e-01, -7.6543e-01],\n",
       "          [-5.0710e-01,  1.6912e+00,  2.3338e-01,  ...,  8.4945e-01,\n",
       "           -1.7268e+00, -3.8647e-01],\n",
       "          [ 1.8517e+00,  2.5161e-01, -1.8888e-01,  ..., -3.5719e-01,\n",
       "            4.4990e-01,  4.5645e-01],\n",
       "          ...,\n",
       "          [-1.5848e+00,  1.2940e+00, -5.3132e-01,  ..., -2.6710e-01,\n",
       "            3.5166e-02, -1.5862e+00],\n",
       "          [ 1.0490e+00,  1.5886e+00,  1.2483e+00,  ...,  8.3320e-01,\n",
       "            1.3358e+00, -1.4040e+00],\n",
       "          [-1.4114e+00, -1.0006e+00, -7.7305e-01,  ...,  1.0748e+00,\n",
       "           -1.5159e+00,  3.4950e-02]],\n",
       "\n",
       "         [[-2.3808e+00,  1.0947e+00,  1.2273e-01,  ...,  1.6483e+00,\n",
       "           -1.3945e+00, -1.3613e+00],\n",
       "          [ 6.8512e-01,  1.3220e+00, -1.3364e+00,  ..., -3.9489e-01,\n",
       "           -4.5790e-02, -1.1463e+00],\n",
       "          [-2.3062e-01,  6.5603e-01, -7.0965e-01,  ..., -3.1086e-01,\n",
       "           -1.7211e-01, -6.2692e-01],\n",
       "          ...,\n",
       "          [ 1.5384e+00,  6.7616e-02,  3.9525e-01,  ..., -6.4299e-01,\n",
       "           -2.7689e-01, -7.5364e-01],\n",
       "          [-1.0342e+00,  2.6525e-01,  1.6355e+00,  ..., -1.2755e-01,\n",
       "            2.3210e+00, -2.2817e+00],\n",
       "          [ 1.1405e-01,  6.7879e-02,  2.0800e-01,  ...,  1.3966e-01,\n",
       "            8.1968e-01, -4.0364e-01]],\n",
       "\n",
       "         [[ 1.6430e-01, -6.4668e-01, -1.7034e+00,  ...,  1.0850e+00,\n",
       "           -1.8012e-01,  8.3131e-01],\n",
       "          [ 6.4307e-01,  3.6770e-01, -6.6582e-01,  ..., -1.2593e+00,\n",
       "            1.2528e+00,  3.0683e-02],\n",
       "          [ 5.5321e-02, -5.0097e-01,  1.0579e-01,  ..., -3.1808e-01,\n",
       "            2.9501e+00, -1.0104e+00],\n",
       "          ...,\n",
       "          [ 5.4906e-01,  7.7921e-02,  7.4522e-01,  ..., -1.2389e+00,\n",
       "            5.8232e-01,  6.1171e-01],\n",
       "          [ 5.5691e-01,  1.3033e+00,  8.5372e-01,  ...,  2.1016e+00,\n",
       "            8.0586e-01, -2.2545e-01],\n",
       "          [-7.7856e-01, -6.6597e-01,  3.7614e-01,  ...,  9.2102e-01,\n",
       "            2.9791e-01, -5.9575e-02]]],\n",
       "\n",
       "\n",
       "        [[[-5.5519e-01, -7.1010e-01, -2.7866e-01,  ..., -4.7519e-01,\n",
       "            4.8875e-01,  5.6178e-01],\n",
       "          [-1.1777e+00, -9.9775e-01,  3.5011e-01,  ..., -1.8767e-01,\n",
       "           -9.6147e-01,  3.4915e-01],\n",
       "          [-5.8658e-01,  5.4702e-01,  4.6620e-01,  ...,  1.9725e+00,\n",
       "           -1.9526e-01, -2.5365e-02],\n",
       "          ...,\n",
       "          [-6.5271e-01, -6.1699e-01,  9.6935e-01,  ..., -1.5275e+00,\n",
       "            1.0928e+00,  2.5346e-02],\n",
       "          [ 2.1702e-01, -1.7966e+00,  1.6770e-01,  ..., -5.7723e-01,\n",
       "           -1.4559e+00, -1.8839e+00],\n",
       "          [ 2.5642e+00, -4.6458e-01,  1.1892e+00,  ...,  1.4338e+00,\n",
       "           -2.4639e-01, -1.0369e+00]],\n",
       "\n",
       "         [[ 8.0991e-01,  4.2052e-01,  2.6899e-03,  ..., -1.2141e+00,\n",
       "           -1.3159e+00,  1.5256e+00],\n",
       "          [ 9.7550e-01, -8.5466e-01, -2.0737e-01,  ..., -2.4176e-03,\n",
       "            1.0690e+00, -6.5578e-01],\n",
       "          [-8.1342e-01,  9.0810e-01, -1.5078e+00,  ..., -2.4583e+00,\n",
       "           -2.7368e-01,  1.3831e+00],\n",
       "          ...,\n",
       "          [ 2.5621e-01, -4.2513e-01, -3.5265e-01,  ...,  1.7768e-01,\n",
       "            1.5545e-01, -8.8761e-01],\n",
       "          [ 2.3743e+00,  1.2694e+00,  2.5772e-01,  ...,  2.2843e-01,\n",
       "           -1.7311e+00,  6.3776e-01],\n",
       "          [ 2.6263e+00,  8.1684e-01,  1.1917e+00,  ...,  7.4842e-01,\n",
       "            9.6150e-01, -1.4256e+00]],\n",
       "\n",
       "         [[ 1.7053e-01, -1.2774e+00, -1.2615e+00,  ..., -7.2421e-01,\n",
       "           -1.2113e+00,  3.9408e-01],\n",
       "          [ 4.3490e-01, -9.7159e-01,  4.8982e-01,  ..., -1.1270e-01,\n",
       "           -4.6322e-01, -5.7960e-01],\n",
       "          [-5.1136e-01, -2.1536e-01, -3.8842e-01,  ...,  6.0560e-01,\n",
       "            5.8752e-01,  1.2259e-01],\n",
       "          ...,\n",
       "          [ 1.7579e-01,  1.5187e-01, -3.1583e-01,  ..., -4.0882e-01,\n",
       "           -1.0689e+00, -4.1229e-01],\n",
       "          [ 3.3589e-01, -3.8419e-01, -1.7024e+00,  ..., -1.2937e-01,\n",
       "           -9.1767e-01, -6.8869e-01],\n",
       "          [ 1.8144e+00, -4.5858e-01,  3.5070e-01,  ..., -5.1570e-01,\n",
       "           -1.2205e+00, -1.3846e+00]]]], grad_fn=<NativeBatchNormBackward0>)"
      ]
     },
     "execution_count": 28,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 28
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-28T06:12:51.086666Z",
     "start_time": "2025-02-28T06:12:51.077348Z"
    }
   },
   "cell_type": "code",
   "source": [
    "bn2d = nn.BatchNorm2d(1)              # 对 3 个通道进行归一化\n",
    "output_4d1 = bn2d(input_4d[:, 0:1, :, :])\n",
    "output_4d1"
   ],
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([[[[ 1.8569e-01,  1.2068e+00,  1.3107e+00,  ...,  4.3335e-01,\n",
       "            9.5957e-01, -4.6191e-01],\n",
       "          [-1.2491e-01, -3.4355e-01, -2.9710e-01,  ...,  5.3335e-01,\n",
       "            1.0790e-01,  9.8546e-01],\n",
       "          [ 1.6000e+00,  1.4632e+00, -9.4793e-01,  ..., -1.3305e-01,\n",
       "            8.2460e-01, -1.5341e+00],\n",
       "          ...,\n",
       "          [-1.7832e-01, -1.9131e-01,  1.3213e+00,  ..., -1.0020e+00,\n",
       "           -1.7615e-01, -9.9070e-01],\n",
       "          [ 1.1259e+00,  7.0162e-01, -1.7411e+00,  ...,  1.5110e+00,\n",
       "           -7.8733e-01,  9.8757e-01],\n",
       "          [ 1.3298e+00,  4.9607e-01,  6.7348e-01,  ...,  2.6917e-01,\n",
       "            5.4652e-01,  9.8298e-01]]],\n",
       "\n",
       "\n",
       "        [[[ 2.1235e-01, -1.3695e+00, -3.8327e-01,  ..., -1.1019e+00,\n",
       "           -1.0343e+00, -2.3676e+00],\n",
       "          [-1.4991e+00,  2.4738e+00,  2.2970e-01,  ..., -1.0718e+00,\n",
       "           -1.2624e+00,  8.9523e-01],\n",
       "          [ 8.4688e-02, -1.4311e+00, -6.3570e-01,  ..., -1.2361e+00,\n",
       "           -1.1776e+00, -2.3710e+00],\n",
       "          ...,\n",
       "          [-4.0124e-01, -3.1967e-01,  5.0613e-01,  ...,  1.0480e+00,\n",
       "           -3.9350e-01, -5.2132e-01],\n",
       "          [ 1.5438e+00,  7.8144e-02,  1.4013e+00,  ...,  2.4039e-01,\n",
       "            2.1614e-01, -1.0379e-01],\n",
       "          [-3.2411e-03, -2.0316e-01, -7.6511e-01,  ...,  2.3886e-01,\n",
       "           -1.9993e-01, -2.3064e-01]]],\n",
       "\n",
       "\n",
       "        [[[ 6.1855e-01, -5.5757e-01, -7.8050e-01,  ...,  1.1679e-01,\n",
       "            9.9641e-04,  1.1030e+00],\n",
       "          [ 7.6553e-01,  1.4823e+00,  1.9650e-01,  ...,  1.8195e-01,\n",
       "           -8.6149e-01,  1.1540e+00],\n",
       "          [ 5.3513e-01, -1.4084e+00,  9.4293e-01,  ...,  8.3426e-01,\n",
       "           -2.4585e-02,  4.4219e-01],\n",
       "          ...,\n",
       "          [ 1.7459e+00,  2.2184e-01,  2.1390e+00,  ..., -6.9334e-01,\n",
       "           -6.6404e-01,  8.6515e-01],\n",
       "          [-5.1798e-01, -1.0526e+00, -1.0209e+00,  ..., -2.1027e+00,\n",
       "            1.8648e+00, -5.9670e-01],\n",
       "          [ 4.7469e-01, -1.2343e+00, -1.6261e-01,  ..., -2.6611e+00,\n",
       "            5.0511e-01,  1.0620e+00]]],\n",
       "\n",
       "\n",
       "        ...,\n",
       "\n",
       "\n",
       "        [[[-1.1727e+00, -8.9828e-01, -1.2812e+00,  ..., -1.3389e-01,\n",
       "            2.6161e-01, -2.7735e-01],\n",
       "          [-1.1142e+00,  9.0828e-01,  5.3890e-02,  ..., -4.1168e-01,\n",
       "            7.6607e-01,  3.3931e-01],\n",
       "          [-1.3843e+00, -3.6305e-01,  6.1533e-01,  ..., -1.5851e-01,\n",
       "           -1.0250e+00, -1.2118e+00],\n",
       "          ...,\n",
       "          [ 2.2697e-01, -4.8767e-01,  1.6945e+00,  ...,  5.2397e-01,\n",
       "           -7.3892e-02, -8.0259e-01],\n",
       "          [ 4.3746e-01,  1.9619e+00,  1.6555e+00,  ..., -8.4203e-01,\n",
       "            1.5130e-01,  6.3055e-02],\n",
       "          [ 2.6801e-01,  1.8562e+00,  2.1875e-01,  ...,  3.8246e-01,\n",
       "            1.7874e+00, -3.3015e-01]]],\n",
       "\n",
       "\n",
       "        [[[-7.3067e-02, -2.1989e-01, -7.8913e-01,  ...,  1.4875e-01,\n",
       "            8.8678e-01, -7.6543e-01],\n",
       "          [-5.0710e-01,  1.6912e+00,  2.3338e-01,  ...,  8.4945e-01,\n",
       "           -1.7268e+00, -3.8647e-01],\n",
       "          [ 1.8517e+00,  2.5161e-01, -1.8888e-01,  ..., -3.5719e-01,\n",
       "            4.4990e-01,  4.5645e-01],\n",
       "          ...,\n",
       "          [-1.5848e+00,  1.2940e+00, -5.3132e-01,  ..., -2.6710e-01,\n",
       "            3.5166e-02, -1.5862e+00],\n",
       "          [ 1.0490e+00,  1.5886e+00,  1.2483e+00,  ...,  8.3320e-01,\n",
       "            1.3358e+00, -1.4040e+00],\n",
       "          [-1.4114e+00, -1.0006e+00, -7.7305e-01,  ...,  1.0748e+00,\n",
       "           -1.5159e+00,  3.4950e-02]]],\n",
       "\n",
       "\n",
       "        [[[-5.5519e-01, -7.1010e-01, -2.7866e-01,  ..., -4.7519e-01,\n",
       "            4.8875e-01,  5.6178e-01],\n",
       "          [-1.1777e+00, -9.9775e-01,  3.5011e-01,  ..., -1.8767e-01,\n",
       "           -9.6147e-01,  3.4915e-01],\n",
       "          [-5.8658e-01,  5.4702e-01,  4.6620e-01,  ...,  1.9725e+00,\n",
       "           -1.9526e-01, -2.5365e-02],\n",
       "          ...,\n",
       "          [-6.5271e-01, -6.1699e-01,  9.6935e-01,  ..., -1.5275e+00,\n",
       "            1.0928e+00,  2.5346e-02],\n",
       "          [ 2.1702e-01, -1.7966e+00,  1.6770e-01,  ..., -5.7723e-01,\n",
       "           -1.4559e+00, -1.8839e+00],\n",
       "          [ 2.5642e+00, -4.6458e-01,  1.1892e+00,  ...,  1.4338e+00,\n",
       "           -2.4639e-01, -1.0369e+00]]]], grad_fn=<NativeBatchNormBackward0>)"
      ]
     },
     "execution_count": 29,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 29
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 训练\n",
    "\n",
    "pytorch的训练需要自行实现，包括\n",
    "1. 定义损失函数\n",
    "2. 定义优化器\n",
    "3. 定义训练步\n",
    "4. 训练"
   ]
  },
  {
   "cell_type": "code",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-28T06:12:51.432863Z",
     "start_time": "2025-02-28T06:12:51.086666Z"
    }
   },
   "source": [
    "from sklearn.metrics import accuracy_score\n",
    "\n",
    "@torch.no_grad()\n",
    "def evaluating(model, dataloader, loss_fct):\n",
    "    loss_list = []\n",
    "    pred_list = []\n",
    "    label_list = []\n",
    "    for datas, labels in dataloader:\n",
    "        datas = datas.to(device)\n",
    "        labels = labels.to(device)\n",
    "        # 前向计算\n",
    "        logits = model(datas)\n",
    "        loss = loss_fct(logits, labels)         # 验证集损失\n",
    "        loss_list.append(loss.item())\n",
    "        \n",
    "        preds = logits.argmax(axis=-1)    # 验证集预测\n",
    "        pred_list.extend(preds.cpu().numpy().tolist())\n",
    "        label_list.extend(labels.cpu().numpy().tolist())\n",
    "        \n",
    "    acc = accuracy_score(label_list, pred_list)\n",
    "    return np.mean(loss_list), acc\n"
   ],
   "outputs": [],
   "execution_count": 30
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### TensorBoard 可视化\n",
    "\n",
    "\n",
    "训练过程中可以使用如下命令启动tensorboard服务。\n",
    "\n",
    "```shell\n",
    "tensorboard \\\n",
    "    --logdir=runs \\     # log 存放路径\n",
    "    --host 0.0.0.0 \\    # ip\n",
    "    --port 8848         # 端口\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-28T06:12:57.542513Z",
     "start_time": "2025-02-28T06:12:51.432863Z"
    }
   },
   "source": [
    "from torch.utils.tensorboard import SummaryWriter\n",
    "\n",
    "\n",
    "class TensorBoardCallback:\n",
    "    def __init__(self, log_dir, flush_secs=10):\n",
    "        \"\"\"\n",
    "        Args:\n",
    "            log_dir (str): dir to write log.\n",
    "            flush_secs (int, optional): write to dsk each flush_secs seconds. Defaults to 10.\n",
    "        \"\"\"\n",
    "        self.writer = SummaryWriter(log_dir=log_dir, flush_secs=flush_secs)\n",
    "\n",
    "    def draw_model(self, model, input_shape):\n",
    "        self.writer.add_graph(model, input_to_model=torch.randn(input_shape))\n",
    "        \n",
    "    def add_loss_scalars(self, step, loss, val_loss):\n",
    "        self.writer.add_scalars(\n",
    "            main_tag=\"training/loss\", \n",
    "            tag_scalar_dict={\"loss\": loss, \"val_loss\": val_loss},\n",
    "            global_step=step,\n",
    "            )\n",
    "        \n",
    "    def add_acc_scalars(self, step, acc, val_acc):\n",
    "        self.writer.add_scalars(\n",
    "            main_tag=\"training/accuracy\",\n",
    "            tag_scalar_dict={\"accuracy\": acc, \"val_accuracy\": val_acc},\n",
    "            global_step=step,\n",
    "        )\n",
    "        \n",
    "    def add_lr_scalars(self, step, learning_rate):\n",
    "        self.writer.add_scalars(\n",
    "            main_tag=\"training/learning_rate\",\n",
    "            tag_scalar_dict={\"learning_rate\": learning_rate},\n",
    "            global_step=step,\n",
    "            \n",
    "        )\n",
    "    \n",
    "    def __call__(self, step, **kwargs):\n",
    "        # add loss\n",
    "        loss = kwargs.pop(\"loss\", None)\n",
    "        val_loss = kwargs.pop(\"val_loss\", None)\n",
    "        if loss is not None and val_loss is not None:\n",
    "            self.add_loss_scalars(step, loss, val_loss)\n",
    "        # add acc\n",
    "        acc = kwargs.pop(\"acc\", None)\n",
    "        val_acc = kwargs.pop(\"val_acc\", None)\n",
    "        if acc is not None and val_acc is not None:\n",
    "            self.add_acc_scalars(step, acc, val_acc)\n",
    "        # add lr\n",
    "        learning_rate = kwargs.pop(\"lr\", None)\n",
    "        if learning_rate is not None:\n",
    "            self.add_lr_scalars(step, learning_rate)\n"
   ],
   "outputs": [],
   "execution_count": 31
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Save Best\n"
   ]
  },
  {
   "cell_type": "code",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-28T06:12:57.547036Z",
     "start_time": "2025-02-28T06:12:57.542513Z"
    }
   },
   "source": [
    "class SaveCheckpointsCallback:\n",
    "    def __init__(self, save_dir, save_step=5000, save_best_only=True):\n",
    "        \"\"\"\n",
    "        Save checkpoints each save_epoch epoch. \n",
    "        We save checkpoint by epoch in this implementation.\n",
    "        Usually, training scripts with pytorch evaluating model and save checkpoint by step.\n",
    "\n",
    "        Args:\n",
    "            save_dir (str): dir to save checkpoint\n",
    "            save_epoch (int, optional): the frequency to save checkpoint. Defaults to 1.\n",
    "            save_best_only (bool, optional): If True, only save the best model or save each model at every epoch.\n",
    "        \"\"\"\n",
    "        self.save_dir = save_dir\n",
    "        self.save_step = save_step\n",
    "        self.save_best_only = save_best_only\n",
    "        self.best_metrics = -1\n",
    "        \n",
    "        # mkdir\n",
    "        if not os.path.exists(self.save_dir):\n",
    "            os.mkdir(self.save_dir)\n",
    "        \n",
    "    def __call__(self, step, state_dict, metric=None):\n",
    "        if step % self.save_step > 0:\n",
    "            return\n",
    "        \n",
    "        if self.save_best_only:\n",
    "            assert metric is not None\n",
    "            if metric >= self.best_metrics:\n",
    "                # save checkpoints\n",
    "                torch.save(state_dict, os.path.join(self.save_dir, \"best.ckpt\"))\n",
    "                # update best metrics\n",
    "                self.best_metrics = metric\n",
    "        else:\n",
    "            torch.save(state_dict, os.path.join(self.save_dir, f\"{step}.ckpt\"))\n",
    "\n"
   ],
   "outputs": [],
   "execution_count": 32
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Early Stop"
   ]
  },
  {
   "cell_type": "code",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-28T06:12:57.551453Z",
     "start_time": "2025-02-28T06:12:57.547036Z"
    }
   },
   "source": [
    "class EarlyStopCallback:\n",
    "    def __init__(self, patience=5, min_delta=0.01):\n",
    "        \"\"\"\n",
    "\n",
    "        Args:\n",
    "            patience (int, optional): Number of epochs with no improvement after which training will be stopped.. Defaults to 5.\n",
    "            min_delta (float, optional): Minimum change in the monitored quantity to qualify as an improvement, i.e. an absolute \n",
    "                change of less than min_delta, will count as no improvement. Defaults to 0.01.\n",
    "        \"\"\"\n",
    "        self.patience = patience\n",
    "        self.min_delta = min_delta\n",
    "        self.best_metric = -1\n",
    "        self.counter = 0\n",
    "        \n",
    "    def __call__(self, metric):\n",
    "        if metric >= self.best_metric + self.min_delta:\n",
    "            # update best metric\n",
    "            self.best_metric = metric\n",
    "            # reset counter \n",
    "            self.counter = 0\n",
    "        else: \n",
    "            self.counter += 1\n",
    "            \n",
    "    @property\n",
    "    def early_stop(self):\n",
    "        return self.counter >= self.patience\n"
   ],
   "outputs": [],
   "execution_count": 33
  },
  {
   "cell_type": "code",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-28T06:12:58.026166Z",
     "start_time": "2025-02-28T06:12:57.551453Z"
    }
   },
   "source": [
    "# 训练\n",
    "def training(\n",
    "    model, \n",
    "    train_loader, \n",
    "    val_loader, \n",
    "    epoch, \n",
    "    loss_fct, \n",
    "    optimizer, \n",
    "    tensorboard_callback=None,\n",
    "    save_ckpt_callback=None,\n",
    "    early_stop_callback=None,\n",
    "    eval_step=500,\n",
    "    ):\n",
    "    record_dict = {\n",
    "        \"train\": [],\n",
    "        \"val\": []\n",
    "    }\n",
    "    \n",
    "    global_step = 0\n",
    "    model.train()\n",
    "    with tqdm(total=epoch * len(train_loader)) as pbar:\n",
    "        for epoch_id in range(epoch):\n",
    "            # training\n",
    "            for datas, labels in train_loader:\n",
    "                datas = datas.to(device)\n",
    "                labels = labels.to(device)\n",
    "                # 梯度清空\n",
    "                optimizer.zero_grad()\n",
    "                # 模型前向计算\n",
    "                logits = model(datas)\n",
    "                # 计算损失\n",
    "                loss = loss_fct(logits, labels)\n",
    "                # 梯度回传\n",
    "                loss.backward()\n",
    "                # 调整优化器，包括学习率的变动等\n",
    "                optimizer.step()\n",
    "                preds = logits.argmax(axis=-1) #最大值的索引\n",
    "            \n",
    "                acc = accuracy_score(labels.cpu().numpy(), preds.cpu().numpy())     # 计算准确率\n",
    "                loss = loss.cpu().item() # 计算损失\n",
    "                # record\n",
    "                \n",
    "                record_dict[\"train\"].append({\n",
    "                    \"loss\": loss, \"acc\": acc, \"step\": global_step # 记录每一步的损失和准确率\n",
    "                })\n",
    "                \n",
    "                # evaluating\n",
    "                if global_step % eval_step == 0:\n",
    "                    model.eval()\n",
    "                    val_loss, val_acc = evaluating(model, val_loader, loss_fct)\n",
    "                    record_dict[\"val\"].append({\n",
    "                        \"loss\": val_loss, \"acc\": val_acc, \"step\": global_step\n",
    "                    })\n",
    "                    model.train()\n",
    "                    \n",
    "                    # 1. 使用 tensorboard 可视化\n",
    "                    if tensorboard_callback is not None:\n",
    "                        tensorboard_callback(\n",
    "                            global_step, \n",
    "                            loss=loss, val_loss=val_loss,\n",
    "                            acc=acc, val_acc=val_acc,\n",
    "                            lr=optimizer.param_groups[0][\"lr\"],\n",
    "                            )\n",
    "                \n",
    "                    # 2. 保存模型权重 save model checkpoint\n",
    "                    if save_ckpt_callback is not None:\n",
    "                        save_ckpt_callback(global_step, model.state_dict(), metric=val_acc)\n",
    "\n",
    "                    # 3. 早停 Early Stop\n",
    "                    if early_stop_callback is not None:\n",
    "                        early_stop_callback(val_acc)\n",
    "                        if early_stop_callback.early_stop:\n",
    "                            print(f\"Early stop at epoch {epoch_id} / global_step {global_step}\")\n",
    "                            return record_dict\n",
    "                    \n",
    "                # udate step\n",
    "                global_step += 1\n",
    "                pbar.update(1)\n",
    "                pbar.set_postfix({\"epoch\": epoch_id})\n",
    "        \n",
    "    return record_dict\n",
    "        \n",
    "\n",
    "epoch = 20\n",
    "\n",
    "model = CNN(num_classes=10)\n",
    "\n",
    "# 1. 定义损失函数 采用交叉熵损失\n",
    "loss_fct = nn.CrossEntropyLoss()\n",
    "# 2. 定义优化器 采用 adam\n",
    "# Optimizers specified in the torch.optim package\n",
    "optimizer = torch.optim.Adam(model.parameters(), lr=0.001)\n",
    "\n",
    "# 1. tensorboard 可视化\n",
    "if not os.path.exists(\"runs\"):\n",
    "    os.mkdir(\"runs\")\n",
    "tensorboard_callback = TensorBoardCallback(\"runs/cifar-10\")\n",
    "tensorboard_callback.draw_model(model, [1, 3, IMAGE_SIZE, IMAGE_SIZE])\n",
    "# 2. save best\n",
    "if not os.path.exists(\"checkpoints\"):\n",
    "    os.makedirs(\"checkpoints\")\n",
    "save_ckpt_callback = SaveCheckpointsCallback(\"checkpoints/cifar-10\", save_step=len(train_dl), save_best_only=True)\n",
    "# 3. early stop\n",
    "early_stop_callback = EarlyStopCallback(patience=5)\n",
    "\n",
    "model = model.to(device)\n"
   ],
   "outputs": [],
   "execution_count": 34
  },
  {
   "cell_type": "code",
   "source": [
    "record = training(\n",
    "    model,\n",
    "    train_dl,\n",
    "    eval_dl,\n",
    "    epoch,\n",
    "    loss_fct,\n",
    "    optimizer,\n",
    "    tensorboard_callback=tensorboard_callback,\n",
    "    save_ckpt_callback=save_ckpt_callback,\n",
    "    early_stop_callback=early_stop_callback,\n",
    "    eval_step=len(train_dl)\n",
    "    )"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2025-02-28T06:18:04.538565Z",
     "start_time": "2025-02-28T06:12:58.026166Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "  0%|          | 0/14080 [00:00<?, ?it/s]"
      ],
      "application/vnd.jupyter.widget-view+json": {
       "version_major": 2,
       "version_minor": 0,
       "model_id": "0972052b544942a2ad26843bd68ee31c"
      }
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Early stop at epoch 8 / global_step 5632\n"
     ]
    }
   ],
   "execution_count": 35
  },
  {
   "cell_type": "code",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-28T06:18:04.737085Z",
     "start_time": "2025-02-28T06:18:04.539563Z"
    }
   },
   "source": [
    "#画线要注意的是损失是不一定在零到1之间的\n",
    "def plot_learning_curves(record_dict, sample_step=500):\n",
    "    # build DataFrame\n",
    "    train_df = pd.DataFrame(record_dict[\"train\"]).set_index(\"step\").iloc[::sample_step]\n",
    "    val_df = pd.DataFrame(record_dict[\"val\"]).set_index(\"step\")\n",
    "\n",
    "    # plot\n",
    "    fig_num = len(train_df.columns)\n",
    "    fig, axs = plt.subplots(1, fig_num, figsize=(5 * fig_num, 5))\n",
    "    for idx, item in enumerate(train_df.columns):    \n",
    "        axs[idx].plot(train_df.index, train_df[item], label=f\"train_{item}\")\n",
    "        axs[idx].plot(val_df.index, val_df[item], label=f\"val_{item}\")\n",
    "        axs[idx].grid()\n",
    "        axs[idx].legend()\n",
    "        # axs[idx].set_xticks(range(0, train_df.index[-1], 5000))\n",
    "        # axs[idx].set_xticklabels(map(lambda x: f\"{int(x/1000)}k\", range(0, train_df.index[-1], 5000)))\n",
    "        axs[idx].set_xlabel(\"step\")\n",
    "    \n",
    "    plt.show()\n",
    "\n",
    "plot_learning_curves(record, sample_step=10)  #横坐标是 steps"
   ],
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<Figure size 1000x500 with 2 Axes>"
      ],
      "image/png": "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"
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "execution_count": 36
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 评估"
   ]
  },
  {
   "cell_type": "code",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-28T06:18:07.528051Z",
     "start_time": "2025-02-28T06:18:04.738082Z"
    }
   },
   "source": [
    "# dataload for evaluating\n",
    "\n",
    "# load checkpoints\n",
    "model.load_state_dict(torch.load(\"checkpoints/cifar-10/best.ckpt\", map_location=\"cpu\"))\n",
    "\n",
    "model.eval()\n",
    "loss, acc = evaluating(model, eval_dl, loss_fct)\n",
    "print(f\"loss:     {loss:.4f}\\naccuracy: {acc:.4f}\")"
   ],
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "loss:     3.1075\n",
      "accuracy: 0.1978\n"
     ]
    }
   ],
   "execution_count": 37
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 推理"
   ]
  },
  {
   "cell_type": "code",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-28T06:48:21.979259Z",
     "start_time": "2025-02-28T06:18:07.529046Z"
    }
   },
   "source": [
    "# test_df\n",
    "test_ds = Cifar10Dataset(\"test\", transform=transforms_eval)\n",
    "test_dl = DataLoader(test_ds, batch_size=batch_size, shuffle=False, drop_last=False)\n",
    "\n",
    "preds_collect = [] # 预测结果收集器\n",
    "model.eval()\n",
    "for data, fake_label in tqdm(test_dl):\n",
    "    data = data.to(device=device)\n",
    "    logits = model(data) #得到预测结果\n",
    "    preds = [test_ds.idx_to_label[idx] for idx in logits.argmax(axis=-1).cpu().tolist()] # 得到预测类别，idx_to_label是id到字符串类别的映射\n",
    "    preds_collect.extend(preds)\n",
    "    \n",
    "test_df[\"label\"] = preds_collect # 增加预测类别列,比赛要求这一列是label\n",
    "test_df.head()"
   ],
   "outputs": [
    {
     "data": {
      "text/plain": [
       "  0%|          | 0/4688 [00:00<?, ?it/s]"
      ],
      "application/vnd.jupyter.widget-view+json": {
       "version_major": 2,
       "version_minor": 0,
       "model_id": "705c55218c8b4108a8ee62978aac1963"
      }
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "                                            filepath class     label\n",
       "0  D:\\Python\\Python_code\\Python_code2025\\day23\\ci...   cat  airplane\n",
       "1  D:\\Python\\Python_code\\Python_code2025\\day23\\ci...   cat  airplane\n",
       "2  D:\\Python\\Python_code\\Python_code2025\\day23\\ci...   cat      bird\n",
       "3  D:\\Python\\Python_code\\Python_code2025\\day23\\ci...   cat  airplane\n",
       "4  D:\\Python\\Python_code\\Python_code2025\\day23\\ci...   cat  airplane"
      ],
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>filepath</th>\n",
       "      <th>class</th>\n",
       "      <th>label</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>D:\\Python\\Python_code\\Python_code2025\\day23\\ci...</td>\n",
       "      <td>cat</td>\n",
       "      <td>airplane</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>D:\\Python\\Python_code\\Python_code2025\\day23\\ci...</td>\n",
       "      <td>cat</td>\n",
       "      <td>airplane</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>D:\\Python\\Python_code\\Python_code2025\\day23\\ci...</td>\n",
       "      <td>cat</td>\n",
       "      <td>bird</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>D:\\Python\\Python_code\\Python_code2025\\day23\\ci...</td>\n",
       "      <td>cat</td>\n",
       "      <td>airplane</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>D:\\Python\\Python_code\\Python_code2025\\day23\\ci...</td>\n",
       "      <td>cat</td>\n",
       "      <td>airplane</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ]
     },
     "execution_count": 38,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 38
  },
  {
   "cell_type": "code",
   "source": [
    "64*4688"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2025-02-28T06:48:21.983064Z",
     "start_time": "2025-02-28T06:48:21.980254Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "300032"
      ]
     },
     "execution_count": 39,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 39
  },
  {
   "cell_type": "code",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-02-28T06:48:22.401477Z",
     "start_time": "2025-02-28T06:48:21.983064Z"
    }
   },
   "source": [
    "# 导出 submission.csv\n",
    "test_df.to_csv(\"submission.csv\", index=False)"
   ],
   "outputs": [],
   "execution_count": 40
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "pytorch",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.8"
  },
  "orig_nbformat": 4
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
